package auth_https

import (
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/rand"
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/pem"
	"math/big"
	"net"
	"os"
	"time"
)

var (
	CaCrtPem   = "./certs/ca.crt"
	CaKeyPem   = "./certs/ca.key"
	serverCert = "./certs/server.crt"
	serverKey  = "./certs/server.key"
	clientCert = "./certs/client.crt"
	clientKey  = "./certs/client.key"
)

func AcEccCerts() ([]byte, []byte, error) {
	// 生成ECC私钥
	priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
	if err != nil {
		return nil, nil, err
	}
	// 生成CA证书模板
	template := x509.Certificate{
		SerialNumber: big.NewInt(1),
		Subject: pkix.Name{
			Organization: []string{"My Organization"},
		},
		NotBefore:             time.Now(),
		NotAfter:              time.Now().AddDate(20, 0, 0),
		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
		BasicConstraintsValid: true,
		IsCA:                  true,
	}

	// 生成CA证书
	caBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
	if err != nil {
		return nil, nil, err
	}

	privBytes, err := x509.MarshalECPrivateKey(priv)
	if err != nil {
		return nil, nil, err
	}

	// 写入CA证书和私钥
	return caBytes, privBytes, err
}

func openCrtToKey(caCrt, caKey string) ([]byte, []byte, error) {
	// 读取CA证书和私钥
	caFile, err := os.Open(caCrt)
	if err != nil {
		return nil, nil, err
	}
	caBytes := make([]byte, 1024)
	n, err := caFile.Read(caBytes)
	if err != nil {
		return nil, nil, err
	}
	err = caFile.Close()
	if err != nil {
		return nil, nil, err
	}

	privFile, err := os.Open(caKey)
	if err != nil {
		return nil, nil, err
	}
	privBytes := make([]byte, 1024)
	n, err = privFile.Read(privBytes)
	if err != nil {
		return nil, nil, err
	}
	err = privFile.Close()
	if err != nil {
		return nil, nil, err
	}

	return caBytes[:n], privBytes[:n], nil
}

// 保存证书
func createCrtToKey(crtPath, keyPath string, crtBytes, keyPriv []byte) error {

	serverFile, err := os.Create(crtPath)
	if err != nil {
		return err
	}
	err = pem.Encode(serverFile, &pem.Block{Type: "CERTIFICATE", Bytes: crtBytes})
	if err != nil {
		return err
	}
	err = serverFile.Close()
	if err != nil {
		return err
	}

	serverPrivFile, err := os.Create(keyPath)
	if err != nil {
		return err
	}
	err = pem.Encode(serverPrivFile, &pem.Block{Type: "EC PRIVATE KEY", Bytes: keyPriv})
	if err != nil {
		return err
	}
	err = serverPrivFile.Close()
	if err != nil {
		return err
	}
	return nil
}

// 服务器证书
func serverCertificate(caBytes, privBytes []byte, netIP []net.IP) ([]byte, []byte, error) {

	caBlock, _ := pem.Decode(caBytes)
	caCert, err := x509.ParseCertificate(caBlock.Bytes)
	if err != nil {
		return nil, nil, err
	}

	privBlock, _ := pem.Decode(privBytes)
	caPriv, err := x509.ParseECPrivateKey(privBlock.Bytes)
	if err != nil {
		return nil, nil, err
	}

	// 生成服务端ECC私钥
	serverPriv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
	if err != nil {
		return nil, nil, err
	}
	// 生成服务端证书模板
	serverTemplate := x509.Certificate{
		SerialNumber: big.NewInt(2),
		Subject: pkix.Name{
			Organization: []string{"My Server"},
		},
		NotBefore:             time.Now(),
		NotAfter:              time.Now().AddDate(5, 0, 0),
		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
		BasicConstraintsValid: true,
		//IPAddresses:           []net.IP{net.ParseIP("127.0.0.1"), net.ParseIP("192.168.114.61")},
		IPAddresses: netIP,
	}

	// 生成服务端证书
	serverBytes, err := x509.CreateCertificate(rand.Reader, &serverTemplate, caCert, &serverPriv.PublicKey, caPriv)
	if err != nil {
		return nil, nil, err
	}
	serverPrivBytes, err := x509.MarshalECPrivateKey(serverPriv)
	if err != nil {
		return nil, nil, err
	}

	// 写入服务端证书和私钥
	return serverBytes, serverPrivBytes, nil
}

// ClientCert 客户端证书
func ClientCert(caBytes, privBytes []byte) ([]byte, []byte, error) {

	caBlock, _ := pem.Decode(caBytes)
	caCert, err := x509.ParseCertificate(caBlock.Bytes)
	if err != nil {
		return nil, nil, err
	}

	privBlock, _ := pem.Decode(privBytes)
	caPriv, err := x509.ParseECPrivateKey(privBlock.Bytes)
	if err != nil {
		return nil, nil, err
	}

	// 生成客户端ECC私钥
	clientPriv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
	if err != nil {
		return nil, nil, err
	}

	// 生成客户端证书模板
	clientTemplate := x509.Certificate{
		SerialNumber: big.NewInt(3),
		Subject: pkix.Name{
			Organization: []string{"My Client"},
		},
		NotBefore:             time.Now(),
		NotAfter:              time.Now().AddDate(5, 0, 0),
		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
		BasicConstraintsValid: true,
	}

	// 生成客户端证书
	clientBytes, err := x509.CreateCertificate(rand.Reader, &clientTemplate, caCert, &clientPriv.PublicKey, caPriv)
	if err != nil {
		return nil, nil, err
	}
	clientPrivBytes, err := x509.MarshalECPrivateKey(clientPriv)
	if err != nil {
		return nil, nil, err
	}

	// 写入客户端证书和私钥
	return clientBytes, clientPrivBytes, nil
}
